import SparkMD5 from 'spark-md5';

interface IWorkerMessage {
  chunks: ArrayBuffer[] | null; // 分块数据
  fileHash?: string | null; // 文件哈希值;
  messageType: 'fail' | 'success' | 'progress'; // 消息类型;
}

self.onmessage = async (e) => {
  const { targetFile, baseChunkSize } = e.data; // 接收主线程传递的文件对象和基础分块大小;
  await slicefile(targetFile, baseChunkSize);
};

// 异步函数，用于将文件分块
// 异步函数，用于将文件分块
async function slicefile(targetFile: File, baseChunkSize: number) {
  return new Promise((resolve, reject) => {
    // 获取File对象的slice方法
    const blobSlice = File.prototype.slice;

    const chunkSize = baseChunkSize * 1024 * 1024; // 分块大小

    const targetChunkCount =
      targetFile && Math.ceil(targetFile.size / chunkSize); // 分块数量

    let currentChunkCount = 0;

    const spark = new SparkMD5.ArrayBuffer();

    const fileReader = new FileReader();

    let fileHash = ''; // 文件哈希值

    const chunks: ArrayBuffer[] = []; // 分块

    const workerMessage: IWorkerMessage = {
      chunks: null, // 分块数据
      fileHash: null, // 文件哈希值;
      messageType: 'progress', // 消息类型;
    };

    // 文件读取成功时的回调函数
    /**
     * 处理文件读取完成事件的回调函数。
     * 该函数负责处理文件分块的读取、哈希计算以及向主线程发送进度和完成消息。
     *
     * @param e - 文件读取事件对象，包含读取的文件数据。
     */
    fileReader.onload = (e) => {
      const curChunk = e.target?.result as ArrayBuffer;

      // 将当前读取的文件分块添加到分块数组中
      chunks.push(curChunk);

      // 将当前分块数据追加到哈希计算器中
      spark.append(curChunk);

      // 增加当前已读取的分块计数
      currentChunkCount++;

      // 如果分块数量达到20个，则发送进度消息给主线程，并清空分块数组
      if (chunks.length >= 20) {
        workerMessage.chunks = chunks;
        workerMessage.messageType = 'progress'; // 消息类型为进度
        self.postMessage(workerMessage); // 发送消息给主线程
        chunks.splice(0, chunks.length); // 清空分块数组
      }

      // 如果当前分块数量达到总分块数，则计算文件哈希值，并发送完成消息给主线程
      if (currentChunkCount >= targetChunkCount) {
        fileHash = spark.end(); // 计算文件哈希值
        if (chunks.length > 0) {
          workerMessage.chunks = chunks;
        }
        workerMessage.fileHash = fileHash; // 文件哈希值
        workerMessage.messageType = 'success'; // 消息类型为成功
        self.postMessage(workerMessage); // 发送消息给主线程
        resolve({ fileHash, chunks }); // 成功回调，返回文件哈希值和分块数据
      } else {
        loadNext(); // 继续读取下一个分块
      }
    };

    // 文件读取失败时的回调函数
    fileReader.onerror = (e) => {
      console.log(e);
      workerMessage.messageType = 'fail';
      self.postMessage(workerMessage); // 发送消息给主线程;
      reject(e); // 失败回调;
    };

    /**
     * 加载下一个文件分块。
     * 该函数用于从目标文件中读取下一个指定大小的分块，并将其作为ArrayBuffer读取。
     * 函数会根据当前已加载的分块数量计算起始和结束位置，确保不会超出文件大小。
     */
    const loadNext = () => {
      // 计算当前分块的起始位置
      const start = currentChunkCount * chunkSize;

      // 计算当前分块的结束位置，确保不会超出文件大小
      const end =
        start + chunkSize >= targetFile.size
          ? targetFile.size
          : start + chunkSize;

      // 使用FileReader读取指定范围的文件分块
      fileReader.readAsArrayBuffer(blobSlice.call(targetFile, start, end));
    };

    loadNext();
  });
}
